package tau.freedbimporter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;
import java.util.regex.Pattern;

import tau.pimpmyfreedb.common.types.Album;
import tau.pimpmyfreedb.common.types.Artist;
import tau.pimpmyfreedb.common.types.MusicItem;
import tau.pimpmyfreedb.common.types.Track;
import tau.pimpmyfreedb.common.types.Tuple;

/*
 * This class takes care of converting RawFreeDBDiscInfo/
 * TrackInfo to Track/Artist/Album/Genre classes.
 */
public class FreeDBDataPimper {
    public class ConvertedData {
	HashMap<String, Artist> artists = new HashMap<String, Artist>();

	public HashMap<String, Artist> getArtists() {
	    return artists;
	}

	public Vector<Tuple<Artist, Album>> getArtistAlbumRelations() {
	    return artistAlbumRelations;
	}

	public Vector<Tuple<Artist, Track>> getArtistTrackRelations() {
	    return artistTrackRelations;
	}

	public Vector<Tuple<Album, Track>> getAlbumTrackRelations() {
	    return albumTrackRelations;
	}

	public Vector<Album> getAlbums() {
	    return albums;
	}

	public Vector<Track> getTracks() {
	    return tracks;
	}

	Vector<Tuple<Artist, Album>> artistAlbumRelations = new Vector<Tuple<Artist, Album>>();
	Vector<Tuple<Artist, Track>> artistTrackRelations = new Vector<Tuple<Artist, Track>>();
	Vector<Tuple<Album, Track>> albumTrackRelations = new Vector<Tuple<Album, Track>>();
	Vector<Album> albums = new Vector<Album>();
	Vector<Track> tracks = new Vector<Track>();
    }

    public ConvertedData convertData(ArrayList<RawFreeDBDiscInfo> discs) {
	ConvertedData result = new ConvertedData();

	// Prepare regular expressions to parse artist / title names:
	// Artist / Album (Year)
	Pattern artistTitleYear = Pattern.compile(".* / .* \\(\\d*\\)");
	// Artist / Album
	Pattern artistTitle = Pattern.compile(".* / .*");

	// Pattern trackWithArtist = Pattern.compile(".* - with .*");
	// Pattern trackFeaturingArtist = Pattern.compile(".* \\(feat. .*\\)");

	for (RawFreeDBDiscInfo di : discs) {

	    // Parse each FreeDB disc
	    String albumArtistName = null;
	    String albumTitle;

	    if (artistTitleYear.matcher(di.getTitle()).matches()) {
		String[] parts = di.getTitle().split(" / ", 2);
		albumArtistName = parts[0];
		albumTitle = parts[1];
	    } else if (artistTitle.matcher(di.getTitle()).matches()) {
		// Artist / Album
		String[] parts = di.getTitle().split(" / ", 2);
		albumArtistName = parts[0];
		albumTitle = parts[1];
	    } else {
		albumTitle = di.getTitle();
		System.out.println("Album title format not recognized: "
			+ albumTitle);
	    }

	    albumTitle = albumTitle.trim();
	    if (albumTitle.length() == 0)
		continue;

	    // Create Album object
	    Album album = new Album(MusicItem.NewItemId, albumTitle,
		    di.getGenre(), di.getYear(), di.getExtendedData());
	    result.albums.add(album);

	    // Create Artist object
	    if (albumArtistName != null
		    && !albumArtistName.equalsIgnoreCase("various")) {
		Artist artist = getOrAddArtist(result.artists, albumArtistName);
		// Relate artist to album
		result.artistAlbumRelations.add(new Tuple<Artist, Album>(
			artist, album));
	    }

	    // Now, parse the individual tracks:
	    for (RawFreeDBTrackInfo ti : di.getTracks()) {
		String trackArtistName;
		String trackTitle;
		if (artistTitle.matcher(ti.getTitle()).matches()) {
		    String[] parts = ti.getTitle().split(" / ");
		    if (parts.length == 2) {
			trackArtistName = parts[0];
			trackTitle = parts[1];
		    } else if (parts.length == 1) {
			trackTitle = parts[0];
			trackArtistName = albumArtistName;
		    } else {
			trackTitle = ti.getTitle();
			trackArtistName = albumArtistName;
		    }
		} else {
		    trackArtistName = albumArtistName;
		    trackTitle = ti.getTitle();
		}
		trackTitle = trackTitle.trim();
		if (trackTitle.isEmpty())
		    trackTitle = "The Song That Had No Name";
		Track track = new Track(MusicItem.NewItemId, trackTitle,
			MusicItem.NewItemId, ti.getLength(),
			ti.getExtendedData());
		result.tracks.add(track);
		if (trackArtistName != null
			&& trackArtistName.trim().length() > 0) {
		    trackArtistName = trackArtistName.trim();
		    Artist trackArtist = getOrAddArtist(result.artists,
			    trackArtistName);
		    result.artistTrackRelations.add(new Tuple<Artist, Track>(
			    trackArtist, track));
		    if (albumArtistName == null
			    || !albumArtistName.equals(trackArtistName)) {
			result.artistAlbumRelations
				.add(new Tuple<Artist, Album>(trackArtist,
					album));
		    }
		}
		if (albumArtistName != null
			&& albumArtistName.trim().length() > 0
			&& !albumArtistName.trim().equals(trackArtistName)) {
		    albumArtistName = albumArtistName.trim();
		    Artist albumArtist = getOrAddArtist(result.artists,
			    albumArtistName);
		    result.artistTrackRelations.add(new Tuple<Artist, Track>(
			    albumArtist, track));
		}

		result.albumTrackRelations.add(new Tuple<Album, Track>(album,
			track));
	    }
	}
	return result;
    }

    private Artist getOrAddArtist(HashMap<String, Artist> artists,
	    String artistName) {
	Artist artist = null;
	if (!artists.containsKey(artistName)) {
	    artist = new Artist(MusicItem.NewItemId, artistName, "");
	    artists.put(artistName, artist);
	    // System.out.println(artistName);
	} else {
	    artist = artists.get(artistName);
	}
	return artist;
    }

}
